package cn.emailChat.ai.service.scheduler;

import cn.emailChat.ai.dto.MailInboundEvent;
import cn.emailChat.ai.domain.Email;
import cn.emailChat.ai.domain.MessageStatus;
import cn.emailChat.ai.common.enums.MessageStatusType;
import cn.emailChat.ai.filterchain.FilterHandler;
import cn.emailChat.ai.repo.EmailRepo;
import cn.emailChat.ai.repo.MessageStatusRepo;
import cn.emailChat.ai.service.util.MailIoUtils;
import cn.emailChat.ai.service.util.MailTextExtractor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.mail.*;
import jakarta.mail.Flags.Flag;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.search.FlagTerm;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@Service
public class MailPoller {

    @Value("${mail.imap.host}") private String host;
    @Value("${mail.imap.port:993}") private int port;
    @Value("${mail.imap.username}") private String username;
    @Value("${mail.imap.password}") private String password;
    @Value("${mail.imap.folder:INBOX}") private String folderName;
    @Value("${mail.imap.use-ssl:true}") private boolean useSsl;
    @Value("${mail.imap.connection-timeout-ms:10000}") private int connectionTimeoutMs;
    @Value("${mail.imap.read-timeout-ms:15000}") private int readTimeoutMs;
    @Value("${mail.imap.mark-seen-after-read:true}") private boolean markSeenAfterRead;

    // —— 分区配置 —— //
    @Value("${mail.reply.partition.count:3}")
    private int partitionCount; // 目前为 3

    // 方案B建议通过 exchange + routingKey 分发；也兼容“直发多个队列”
    @Value("${mail.reply.partition.exchange:auto.reply.x}")
    private String replyExchange; // 若不用交换机，可设为空字符串 ""

    // routingKey 前缀，例如 auto.reply.p0 / auto.reply.p1 / auto.reply.p2
    @Value("${mail.reply.partition.routing-prefix:auto.reply.p}")
    private String replyRoutingPrefix;

    // 如果直发队列，配置三个队列的前缀：auto.reply.q.p0/1/2
    @Value("${mail.reply.partition.queue-prefix:auto.reply.q.p}")
    private String replyQueuePrefix;

    @Autowired
    private EmailRepo emailRepo;

    @Autowired
    private MessageStatusRepo messageStatusRepo;

    private final RabbitTemplate rabbitTemplate;

    private final FilterHandler filterChain;

    private volatile Session session;
    private volatile Store store;

    public MailPoller(RabbitTemplate rabbitTemplate, FilterHandler filterChain) {
        this.rabbitTemplate = rabbitTemplate;
        this.filterChain = filterChain;
    }

    @PostConstruct
    public void init() {
        session = Session.getInstance(buildProps());
    }

    @PreDestroy
    public void shutdown() {
        MailIoUtils.closeQuietly(store);
    }

    private Properties buildProps() {
        Properties p = new Properties();
        p.put("mail.store.protocol", useSsl ? "imaps" : "imap");
        p.put("mail.imap.connectiontimeout", String.valueOf(connectionTimeoutMs));
        p.put("mail.imap.timeout", String.valueOf(readTimeoutMs));
        if (useSsl) {
            p.put("mail.imap.ssl.enable", "true");
            p.put("mail.imap.port", String.valueOf(port));
        }
        p.put("mail.imap.heartbeat.interval", "60");
        return p;
    }

    private synchronized void ensureStoreConnected() throws MessagingException {
        if (store == null) {
            store = session.getStore(useSsl ? "imaps" : "imap");
        }
        if (!store.isConnected()) {
            store.connect(host, port, username, password);
        }
    }

    private Folder openFolder() throws MessagingException {
        Folder folder = store.getFolder(folderName);
        if (!folder.isOpen()) {
            folder.open(Folder.READ_WRITE);
        }
        return folder;
    }

    @Scheduled(fixedDelayString = "#{${mail.imap.poll-seconds:300} * 1000}")
    public void pollUnreadMails() {
        Folder folder = null;
        boolean businessOk = false;

        try {
            ensureStoreConnected();
            folder = openFolder();

            // 1) 搜索未读
            Message[] messages = folder.search(new FlagTerm(new Flags(Flag.SEEN), false));
            System.out.println("[MailPoller] 未读邮件总数: " + messages.length);

            if (messages.length == 0) {
                businessOk = true;
                return;
            }

            // 2) **按接收时间升序排序**
            List<Message> sorted = Arrays.stream(messages)
                    .sorted(Comparator.comparing(m -> {
                        Date r = MailIoUtils.safe(m::getReceivedDate);
                        return (r == null) ? new Date(0L) : r;
                    }))
                    .toList();

            // 3) 依次处理并**按分区投递**
            for (Message msg : sorted) {
                String subject = MailIoUtils.safe(msg::getSubject);
                Address[] from = MailIoUtils.safe(msg::getFrom);
                Date received = MailIoUtils.safe(msg::getReceivedDate);

                String fromEmail = null;
                if (from != null && from.length > 0 && from[0] instanceof InternetAddress) {
                    fromEmail = ((InternetAddress) from[0]).getAddress();
                }

                // 使用过滤责任链进行过滤
                if (!filterChain.filter(fromEmail)) {
                    System.out.println("[MailPoller] 未通过过滤器链，跳过: from=" + fromEmail + ", subject=" + subject);
                    if (markSeenAfterRead) {
                        msg.setFlag(Flag.SEEN, true);
                    }
                    continue;
                }

                // 提取正文
                String text = MailTextExtractor.extractBestText(msg);

                // 生成/解析 messageId
                String messageId = resolveMessageId(folder, msg, fromEmail, received);

                // === 邮件表：查重 + 写入 ===
                Optional<Email> emailOpt = emailRepo.findByMessageId(messageId);
                if (emailOpt.isPresent() && Boolean.TRUE.equals(emailOpt.get().getProcessed())) {
                    System.out.println("[MailPoller] 邮件已处理，跳过: " + messageId);
                    continue;
                }

                Email email = emailOpt.orElseGet(Email::new);
                email.setMessageId(messageId);
                email.setFromEmail(fromEmail);
                email.setSubject(subject);
                email.setBody(text);
                email.setSendTime(toLocalDateTime(received));
                email.setProcessed(false);
                emailRepo.save(email);

                // === 消息状态表：投递前先写入 PENDING ===
                MessageStatus status = messageStatusRepo.findByMessageId(messageId)
                        .orElseGet(MessageStatus::new);
                status.setMessageId(messageId);
                // 这里记录 exchangeName 或 “queuePrefix+pX”，仅作为追踪字段
                status.setExchangeName(replyExchange != null && !replyExchange.isEmpty()
                        ? replyExchange
                        : (replyQueuePrefix + "X")); // 占位记录
                status.setStatus(MessageStatusType.PENDING);
                if (status.getRetryCount() == null) status.setRetryCount(0);
                LocalDateTime now = LocalDateTime.now();
                if (status.getCreateTime() == null) status.setCreateTime(now);
                status.setUpdateTime(now);
                messageStatusRepo.save(status);

                // === 计算分区 & 投递 ===
                int partition = computePartition(fromEmail, partitionCount);
                String routingKey = replyRoutingPrefix + partition;
//                String queueName  = replyQueuePrefix + partition;

                MailInboundEvent event = new MailInboundEvent(
                        messageId, subject, fromEmail, username, received, text
                );

                // 方案B推荐：发到交换机，使用 routingKey 分区
                rabbitTemplate.convertAndSend(replyExchange, routingKey, event);
                System.out.println("[MailPoller] MQ 已投递 exchange=" + replyExchange
                        + ", routingKey=" + routingKey + ", event=" + event);

                // 标记已读
                if (markSeenAfterRead) {
                    msg.setFlag(Flag.SEEN, true);
                }
            }

            businessOk = true;

        } catch (AuthenticationFailedException ae) {
            System.err.println("[MailPoller] 认证失败: " + ae.getMessage());
        } catch (FolderClosedException fce) {
            System.err.println("[MailPoller] FolderClosed: " + fce.getMessage());
        } catch (StoreClosedException sce) {
            System.err.println("[MailPoller] StoreClosed: " + sce.getMessage());
        } catch (MessagingException me) {
            System.err.println("[MailPoller] Messaging 异常: " + me.getMessage());
        } catch (Exception e) {
            System.err.println("[MailPoller] 业务处理异常: " + e.getMessage());
        } finally {
            MailIoUtils.closeQuietly(folder);
            if (!businessOk) {
                MailIoUtils.closeQuietly(store);
                store = null;
            }
        }
    }

    private int computePartition(String fromEmail, int n) {
        if (n <= 0) return 0;
        if (fromEmail == null) return 0;
        return Math.floorMod(fromEmail.hashCode(), n);
    }

    private String resolveMessageId(Folder folder, Message msg, String fromEmail, Date received) {
        String messageId = MailIoUtils.safe(() -> {
            String[] h = msg.getHeader("Message-ID");
            return (h != null && h.length > 0) ? h[0] : null;
        });
        if (messageId != null && !messageId.isEmpty()) return messageId;

        try {
            if (folder instanceof UIDFolder uf) {
                long uid = uf.getUID(msg);
                if (uid > 0) return "UID-" + uid;
            }
        } catch (Throwable ignored) {}

        String safeFrom = (fromEmail == null || fromEmail.isEmpty()) ? "unknown" : fromEmail;
        long ts = (received == null) ? System.currentTimeMillis() : received.getTime();
        String fallback = safeFrom + "_" + ts + "_" + UUID.randomUUID();
        System.out.println("[MailPoller] Message-ID 缺失，使用 fallbackId=" + fallback);
        return fallback;
    }

    private static LocalDateTime toLocalDateTime(Date date) {
        if (date == null) return null;
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }
}
